package com.smart.es;

import com.smart.es.entity.Product;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;


/**
 * 索引 Index 操作
 * 数据操作
 * 增
 * 删
 * 改
 * <p>
 * 查
 * 多条键查询
 * 分页查询
 */
@SpringBootTest
@Slf4j
public class ProductDaoSelect {
    @Resource
    ElasticsearchRestTemplate template;

    @Test
    void testSave() {
        List<IndexQuery> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Product product = new Product();
            long id = (long) i + 1;
            product.setProductId(id);
            product.setTitle("杯子" + i);
            BigDecimal divide = new BigDecimal("1000").subtract(new BigDecimal(i + 1));
            product.setPrice(divide);
            IndexQuery indexQuery = new IndexQuery();
            indexQuery.setObject(product);
            list.add(indexQuery);
        }
        template.bulkIndex(list, Product.class);
    }


    /**
     * 通过ID查询
     */
    @Test
    void testFind() {
        Product product = template.get("123456", Product.class);
        assert product != null;
        log.info(product.getTitle());
    }

    /**
     * 查询核心类
     * CriteriaQuery 使用原生命令     post  _search/_doc/index_1
     * <p>
     * StringQuery 使用类似注解的方式
     * <p>
     * NativeSearchQuery(常用)
     * 实现复杂的查询需要使用该类
     */
    @Test
    void testMultiGet() {
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        NativeSearchQuery nsq = new NativeSearchQuery(matchAllQueryBuilder);
        List<MultiGetItem<Product>> multiGetItems = template.multiGet(nsq, Product.class);
        multiGetItems.forEach(multiGetItem -> {
            Product product = multiGetItem.getItem();
            log.info(product.getTitle());
        });
    }

    /**
     *
     * 第一步通过template的search方法索引
     * 第二步创建Query(NativeSearchQuery)对象
     * 第三步创建 QueryBuilder对象
     *
     *
     * high  level   client
     *
     * QueryBuilder
     * 大于  小于
     * 等于
     * 范围
     * 模糊查询
     * 精确查询
     * 组合   and   or
     * 高亮查询
     * 聚合查询 分组
     * 排序
     *
     *
     */

    /**
     * 核心方法 search
     */
    @Test
    void testSearch() {
        //
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        NativeSearchQuery nsq = new NativeSearchQuery(matchAllQueryBuilder);
        SearchHits<Product> search = template.search(nsq, Product.class);
    }

    /**
     * 等值查询   ==
     */
    @Test
    void testSearchQueryBuilder() {
        // 主要作用用于拼接多条键
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        // and  或者  or

//        AND
        qb.must();
        // 相当于OR
        qb.should();
        NativeSearchQuery nsq = new NativeSearchQueryBuilder()
                .withQuery(qb)
                .build();

        SearchHits<Product> search = template.search(nsq, Product.class);
        List<Product> products = new ArrayList<>();
        search.getSearchHits().forEach(hit -> {
            Product product = hit.getContent();
            products.add(product);
        });

    }

    /**
     * 大于等于  大于  小于  小于等于
     */

    @Test
    void testSearchRangeQueryBuilder() {

//        RangeQueryBuilder qb = QueryBuilders.rangeQuery("title");

//        qb.gte()
//        qb.gt()
//        qb.lt()
//        qb.lte()
//        qb.from(10);
//        qb.to(100);

        RangeQueryBuilder qb = QueryBuilders.rangeQuery("price");
        qb.from(300, true).to(1000, true);
        NativeSearchQuery nsq = new NativeSearchQueryBuilder()
                .withQuery(qb)
                .build();

        SearchHits<Product> search = template.search(nsq, Product.class);
        search.getSearchHits().forEach(hit -> {
            Product product = hit.getContent();
            log.info(product.getPrice().toString());
        });
    }


    /**
     * abc
     * <p>
     * abc
     */
    @Test
    void testMatchPhraseQueryBuilder() {
        // 精确匹配 (英文) 不会分词
//        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery();
        // 中文精确匹配
        MatchPhraseQueryBuilder qb = QueryBuilders.matchPhraseQuery("title", "手机");

        NativeSearchQuery nsq = new NativeSearchQueryBuilder()
                .withQuery(qb)
                .build();

        SearchHits<Product> search = template.search(nsq, Product.class);
        search.getSearchHits().forEach(hit -> {
            Product product = hit.getContent();
            log.info(product.getPrice().toString());
        });
    }

    /**
     * 模糊查询
     */
    @Test
    void testWildcardQueryBuilder() {
        WildcardQueryBuilder qb = QueryBuilders.wildcardQuery("title", "手");
        NativeSearchQuery nsq = new NativeSearchQueryBuilder()
                .withQuery(qb)
                .build();
        SearchHits<Product> search = template.search(nsq, Product.class);
        search.getSearchHits().forEach(hit -> {
            Product product = hit.getContent();
            log.info(product.getPrice().toString());
        });
    }

    /**
     *
     */
    @Test
    void testQueryBuilder() {
        //查询商品的标题 并且价格小于1000
        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        // and
        // 模糊查询商品标题手
        WildcardQueryBuilder query = QueryBuilders.wildcardQuery("title", "手");
        // 价格小于
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").lt("1000");

        qb.must(query).must(rangeQueryBuilder);

        NativeSearchQuery nsq = new NativeSearchQueryBuilder()
                .withQuery(qb)
                .build();
        SearchHits<Product> hits = template.search(nsq, Product.class);
    }


    @Test
    void testQueryBuilder2() {
//        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery();

        // 模糊查询商品标题手
        // ?匹配单个  *  匹配多个

//        WildcardQueryBuilder query = QueryBuilders.wildcardQuery("title", "*机*");
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();

        PageRequest pageRequest = PageRequest.of(0, 10);

        /**
         * 分页操作 withPageable
         * PageRequest.of()
         *
         * 过滤列 withFields
         *
         * 设置高亮   withHighlightBuilder
         *
         */
        HighlightBuilder builder = new HighlightBuilder();
        builder.field("title");
        NativeSearchQuery nsq = new NativeSearchQueryBuilder()
                .withQuery(matchAllQueryBuilder)
                .withPageable(pageRequest)
//                .withFields("title","price")
                .withHighlightBuilder(builder)

                .build();
        SearchHits<Product> hits = template.search(nsq, Product.class);
        hits.forEach(hit -> {
            Product content = hit.getContent();
            log.info(content.getTitle());
        });
    }

}